use std::collections::HashMap;

pub fn mymod_str(){
    println!("{:?}", "mymod");
}

/// rust 1.27.2编译通过，但是有警告好像


/// base64 编码 算法很烂，还有巨大优化空间
pub fn base64encode(code: &String) -> String {
    let mut result = String::from(""); // 结果变量
    let bytes = code.as_bytes(); // utf-8转换的byte数组，数据基准
    let len = bytes.len(); // 数组长度
    let mut byte_array:[u8;3] = [0;3]; // u8;3单个数组
    let mut byte_vec:Vec<[u8;3]> = Vec::new(); // 存放u8;3的队列
    for (i, &item) in bytes.iter().enumerate() { // 循环byte数组
        let y = i%3; // 获得余数 数组角标 
        byte_array[y] = item; // byte拷贝值存入 u8;3 数组//不用clone()也没问题
        if y == 2 || i == (len -1) { // 存到一组结尾，和总结尾时 
            // println!(" push {:?}", &byte_array);
            byte_vec.push(byte_array); // 整体拷贝u8;3数组到 转换队列中，这里没用clone()，居然也行！
            byte_array = [0;3]; // 重置u8;3数组
        }
    }
    println!(" byte_vec == {:?}", byte_vec); // 打印一下
    let b_len = byte_vec.len(); // u8;3数组队列长度

    for (i, &item) in byte_vec.iter().enumerate() { // 循环u8;3 队列 vector
        let a4 = trans_a4(&item); // 转换 u8;4 数组
        //
        result.push(b64_to_char(a4[0])); // 这里后面都是根据对照表提取字符然后存入转换结果
        result.push(b64_to_char(a4[1]));
        if b_len == i + 1 { // 结尾处理
            if a4[2] == 0u8 {
                result.push('='); // 结尾处要独立处理 = 号的问题
            } else{
                result.push(b64_to_char(a4[2]));
            }
            if a4[3] == 0u8 {
                result.push('=');
            } else {
                result.push(b64_to_char(a4[3]));
            }
        } else { // 非结尾处理
            result.push(b64_to_char(a4[2]));
            result.push(b64_to_char(a4[3]));
        }
    }
    result
}


/// base64 解码 算法很烂，还有巨大优化空间
pub fn base64decode(code: &String) -> String {
    let mut u8_vec:Vec<u8> = Vec::new(); // 结果队列，byte队列，到字符串还要转换一下
    let mut num_array:[u8;4] = [0;4]; // 单个 u8;4数组
    let mut num_vec:Vec<[u8;4]> = Vec::new(); // u8;4数组队列
    let chars = code.chars(); // base64编码字符队列
    let len = code.len(); // base64编码长度
    for (i, item) in chars.enumerate(){ // 循环此编码字符队列
        
        let y = i%4; // 用余数分组，每4个为一组
        if item == '=' { // 单独处理=号结尾
            num_array[y] = 0u8;
        } else {
            let n = b64_to_num(item); // 将字符对应的编号找到！注意这里传入=在对照表是找不到的
            num_array[y] = n; // 拷贝值存入数组，是不是要拷贝值？不确定。变量归属和声明周期还不熟（不clone也行呢）
        }
        if y == 3 || i == (len - 1) { // 分组结尾 和 整个队列结尾单独处理
            num_vec.push(num_array); // 将u8;4数组拷贝到 队列中// 不拷贝（clone）也行
        }
    }

    println!(" num_vec == {:?}", num_vec); // 打印中间结果
    let n_len = num_vec.len(); // 计算u8;4数组队列长度

    for (i, &item) in num_vec.iter().enumerate() { // 开始循环u8;4数组队列
        let a3 = trans_a3(&item); //反向转换 将u8;4数组转换成u8;3数组
        u8_vec.push(a3[0]); //将u8;3数组存储到中间byte队列中
        if i == n_len - 1 { // 单独处理结尾的情况
            if a3[1] != 0u8 {
                u8_vec.push(a3[1]);
            }
            if a3[2] != 0u8 {
                u8_vec.push(a3[2]);
            }
        } else {
            u8_vec.push(a3[1]);
            u8_vec.push(a3[2]);
        }
    }
    let result = String::from_utf8(u8_vec).unwrap(); // 这里将u8;3队列转换成utf-8字符串
    result
}

/// 这是个样本方法，摘抄来参考的 base64没用到此方法
pub fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}


/// u8;3 数组转换 u8;4数组
pub fn trans_a4(a3:&[u8;3]) -> [u8;4]{
    // 就是3位8byte，转换成4位6byte组
    let mut a4:[u8;4] = [0;4];
    a4[0] = a3[0]>>2;//0右移2位
    a4[1] = (a3[0]<<6)>>2|a3[1]>>4;//0左移6位再右移2位和1右移4位组合
    a4[2] = (a3[1]<<4)>>2|a3[2]>>6;//1左移4位再右移2位和2右移6位组合
    a4[3] = (a3[2]<<2)>>2;//2左移2位再右移2位//其实可以直接将左两位异或0b00
    a4
}

/// u8;4 数组转换 u8;3数组
pub fn trans_a3(a4:&[u8;4]) -> [u8;3]{
    // 就是4位6byte，转换成3位8byte组
    let mut a3:[u8;3] = [0;3];
    a3[0] = a4[0]<<2|a4[1]>>4;//0左移2位组合1右移4位
    a3[1] = a4[1]<<4|a4[2]>>2;//1左移4位组合2右移2位
    a3[2] = a4[2]<<6|a4[3];//2左移6位组合3全部
    a3
}

// map形式的
// let mut b64map = HashMap::new();
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');
// b64map.insert(0, 'A');

/// 用key 获取char
pub fn b64_to_char(key:u8) -> char {
    // 下面这段程序用B64_ARY当作查询基准 也可以运行
    // let mut c:char = ' ';
    // for pat in B64_ARY.iter() {
    //     if pat.0 == key {
    //         c = pat.1;
    //         break;
    //     }
    // }
    // c
    // 下面是用 B64_STR 做基准查询 str.get 方法没用上，以后研究
    let mut c:char = '-';
    let mut i:u64 = 0;
    for pat in B64_STR.chars() {
        if i == key as u64 {
            c = pat;
            break;
        }
        i+=1;
    }
    c
}

/// 用char 获取 key编号
pub fn b64_to_num(key:char) -> u8 {
    // 下面这段程序用B64_ARY当作查询基准 也可以运行
    // let mut n:u8 = 0;
    // for pat in B64_ARY.iter() {
    //     if pat.1 == key {
    //         n = pat.0;
    //         break;
    //     }
    // }
    // n
    // 下面是用 B64_STR 做基准查询
    if key == '='{ //如果查询= 直接返回0
        return 0 as u8
    }
    let n = B64_STR.find(key).unwrap();
    n as u8
}

// 元祖数组类型 b64对照表
const B64_ARY:[(u8, char);64] = [
(0,'A'),(1,'B'),(2,'C'),(3,'D'),(4,'E'),(5,'F'),(6,'G'),(7,'H'),
(8,'I'),(9,'J'),(10,'K'),(11,'L'),(12,'M'),(13,'N'),(14,'O'),(15,'P'),
(16,'Q'),(17,'R'),(18,'S'),(19,'T'),(20,'U'),(21,'V'),(22,'W'),(23,'X'),
(24,'Y'),(25,'Z'),(26,'a'),(27,'b'),(28,'c'),(29,'d'),(30,'e'),(31,'f'),
(32,'g'),(33,'h'),(34,'i'),(35,'j'),(36,'k'),(37,'l'),(38,'m'),(39,'n'),
(40,'o'),(41,'p'),(42,'q'),(43,'r'),(44,'s'),(45,'t'),(46,'u'),(47,'v'),
(48,'w'),(49,'x'),(50,'y'),(51,'z'),(52,'0'),(53,'1'),(54,'2'),(55,'3'),
(56,'4'),(57,'5'),(58,'6'),(59,'7'),(60,'8'),(61,'9'),(62,'+'),(63,'/')
];


// const B64_MAP:HashMap<u8, char> = [(0, 'A')].iter().cloned().collect();
// str类型 b64对照表
const B64_STR:&'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


